<?php

namespace Dongasai\WkProtoPhp\Enums;

/**
 * 设置标志位枚举
 * 使用PHP 8枚举语法
 */
enum SettingFlag: int
{
    case RECEIPT_ENABLED = 1 << 7; // 是否开启回执
    case SIGNAL = 1 << 5;          // 是否开启signal加密
    case NO_ENCRYPT = 1 << 4;     // 是否不加密
    case TOPIC = 1 << 3;           // 是否有topic
    case STREAM = 1 << 1;          // 是否开启流

    /**
     * 获取标志位的字符串表示
     */
    public function toString(): string
    {
        return $this->name;
    }

    /**
     * 获取标志位描述
     */
    public function getDescription(): string
    {
        return match ($this) {
            self::RECEIPT_ENABLED => '开启回执',
            self::SIGNAL => 'Signal加密',
            self::NO_ENCRYPT => '不加密',
            self::TOPIC => '包含话题',
            self::STREAM => '开启流',
        };
    }

    /**
     * 从值创建枚举实例
     */
    public static function fromValue(int $value): self
    {
        return self::from($value);
    }
}

/**
 * 设置类 - 封装多个设置标志位的组合
 */
class Setting
{
    // 向后兼容的常量
    public const UNKNOWN = 0;
    public const RECEIPT_ENABLED = 1 << 7; // 是否开启回执
    public const SIGNAL = 1 << 5;          // 是否开启signal加密
    public const NO_ENCRYPT = 1 << 4;     // 是否不加密
    public const TOPIC = 1 << 3;           // 是否有topic
    public const STREAM = 1 << 1;          // 是否开启流
    
    private int $value = 0;

    public function __construct(int $value = 0)
    {
        $this->value = $value;
    }

    /**
     * 向后兼容的isSet方法
     */
    
    public function getValue(): int
    {
        return $this->value;
    }

    public function setValue(int $value): void
    {
        $this->value = $value;
    }

    public function isSet(SettingFlag|int $flag): bool
    {
        if ($flag instanceof SettingFlag) {
            return ($this->value & $flag->value) !== 0;
        } else {
            return ($this->value & $flag) !== 0;
        }
    }

    public function set(SettingFlag $flag): void
    {
        $this->value |= $flag->value;
    }

    public function clear(SettingFlag $flag): void
    {
        $this->value &= ~$flag->value;
    }

    public function toUint8(): int
    {
        return $this->value & 0xFF;
    }

    public function hasReceiptEnabled(): bool
    {
        return $this->isSet(SettingFlag::RECEIPT_ENABLED);
    }

    public function hasSignal(): bool
    {
        return $this->isSet(SettingFlag::SIGNAL);
    }

    public function hasNoEncrypt(): bool
    {
        return $this->isSet(SettingFlag::NO_ENCRYPT);
    }

    public function hasTopic(): bool
    {
        return $this->isSet(SettingFlag::TOPIC);
    }

    public function hasStream(): bool
    {
        return $this->isSet(SettingFlag::STREAM);
    }

    public function setReceiptEnabled(bool $enabled): void
    {
        if ($enabled) {
            $this->set(SettingFlag::RECEIPT_ENABLED);
        } else {
            $this->clear(SettingFlag::RECEIPT_ENABLED);
        }
    }

    public function setSignal(bool $enabled): void
    {
        if ($enabled) {
            $this->set(SettingFlag::SIGNAL);
        } else {
            $this->clear(SettingFlag::SIGNAL);
        }
    }

    public function setNoEncrypt(bool $enabled): void
    {
        if ($enabled) {
            $this->set(SettingFlag::NO_ENCRYPT);
        } else {
            $this->clear(SettingFlag::NO_ENCRYPT);
        }
    }

    public function setTopic(bool $enabled): void
    {
        if ($enabled) {
            $this->set(SettingFlag::TOPIC);
        } else {
            $this->clear(SettingFlag::TOPIC);
        }
    }

    public function setStream(bool $enabled): void
    {
        if ($enabled) {
            $this->set(SettingFlag::STREAM);
        } else {
            $this->clear(SettingFlag::STREAM);
        }
    }

    public function __toString(): string
    {
        $flags = [];
        if ($this->hasReceiptEnabled()) $flags[] = 'RECEIPT_ENABLED';
        if ($this->hasSignal()) $flags[] = 'SIGNAL';
        if ($this->hasNoEncrypt()) $flags[] = 'NO_ENCRYPT';
        if ($this->hasTopic()) $flags[] = 'TOPIC';
        if ($this->hasStream()) $flags[] = 'STREAM';
        
        return empty($flags) ? 'UNKNOWN' : implode('|', $flags);
    }

    /**
     * 获取所有设置的标志位
     */
    public function getFlags(): array
    {
        $flags = [];
        foreach (SettingFlag::cases() as $flag) {
            if ($this->isSet($flag)) {
                $flags[] = $flag;
            }
        }
        return $flags;
    }

    /**
     * 检查是否需要加密
     */
    public function requiresEncryption(): bool
    {
        return !$this->hasNoEncrypt();
    }

    /**
     * 获取加密级别
     */
    public function getEncryptionLevel(): string
    {
        if ($this->hasNoEncrypt()) {
            return 'none';
        } elseif ($this->hasSignal()) {
            return 'signal';
        } else {
            return 'standard';
        }
    }
}